package com.fast.develop.management.resource.compoment;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fast.develop.core.io.ResourceManager;
import com.fast.develop.management.resource.emuns.ResourceType;
import com.fast.develop.management.resource.utils.SchemaFileUtil;
import com.fast.develop.management.resource.vo.ResourceVo;
import com.fast.develop.management.resource.vo.TreeVo;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 莫寅
 * @createTime 2022-06-12 13:21
 * @desc：
 */
public class TreeReader {

    private ResourceManager resourceManager;

    private SchemaReader schemaReader;

    public TreeReader(ResourceManager resourceManager, SchemaReader schemaReader) {
        this.resourceManager = resourceManager;
        this.schemaReader = schemaReader;
    }

    private List<TreeVo> sort(List<TreeVo> trees){
        List<TreeVo> sortedTree = trees.stream().sorted((x,y) -> {
            ResourceVo resource = (ResourceVo) y.getData();
            if(resource.getType() == ResourceType.domain_model_field_primary_key){
                return 1;
            }else{
                return x.getTitle().compareTo(y.getTitle());
            }
        }).map(treeVo -> {
            if(treeVo.getChildren() != null){
                treeVo.setChildren(sort(treeVo.getChildren()));
            }
            return treeVo;
        }).collect(Collectors.toList());
        return sortedTree;
    }

    public List<TreeVo> get(Collection<String> folderNames, Collection<String> fileNames, ResourceType resourceType){
        List<TreeVo> resources = new ArrayList<>();

        //从根目录开始
        List<TreeVo> rootTreeResources = fileNames.stream()
                .filter(s -> SchemaFileUtil.filterFile(s) && s.indexOf(StrUtil.SLASH) == -1)
                .map(s -> createTreeDto(s, false, ResourceType.domain_model))
                .collect(Collectors.toList());

        List<TreeVo> folderTreeResources = getTree(folderNames, "", fileNames, resourceType);

        resources.addAll(rootTreeResources);
        resources.addAll(folderTreeResources);

        return sort(resources);
    }

    private List<TreeVo> getTree(Collection<String> folderNames, String folderPath, Collection<String> fileNames, ResourceType resourceType){

        List<TreeVo> resources = new ArrayList<>();

        //找到folderPath下的子目录
        List<String> childResources = folderNames.stream()
                .filter(s -> SchemaFileUtil.filterFolder(s) && isFolderChild(folderPath, s))
                .collect(Collectors.toList());

        //未处理资源
        List<String> untreatedResources = folderNames.stream()
                .filter(s -> !childResources.contains(s))
                .collect(Collectors.toList());

        List<TreeVo> childResourcesTree = childResources.stream()
                .map(s -> {
                    TreeVo treeDto = getResourceVo(s, fileNames, resourceType);
                    treeDto.getChildren().addAll(getTree(untreatedResources, s, fileNames, resourceType));
                    return treeDto;
                })
                .collect(Collectors.toList());


        resources.addAll(childResourcesTree);

        return resources;
    }

    private boolean isFolderChild(String parentFolderPath, String folderPath){
        //等于的话不是子集
        if(parentFolderPath.equalsIgnoreCase(folderPath)){
            return false;
        }
        //不是子目录
        if(folderPath.indexOf(parentFolderPath) == -1 || folderPath.indexOf(parentFolderPath) > 0){
            return false;
        }

        String[] props = folderPath.split(parentFolderPath+StrUtil.SLASH);
        String path;
        if(StrUtil.isBlank(parentFolderPath)){
            path = folderPath;
        }else if(props.length > 1){
            path = props[1];
        }else{
            path = folderPath;
        }

        if(path.indexOf(StrUtil.SLASH) == -1){
            return true;
        }else{
            return false;
        }
    }

    private TreeVo getResourceVo(String fullPath, Collection<String> fileNames, ResourceType resourceType){

        TreeVo folderResource = createTreeDto(fullPath, true, resourceType);

        List<String> folderFilePaths = fileNames.stream().filter(s -> {
            String[] props = s.split(fullPath + StrUtil.SLASH);
            if(props.length > 1){
                if(props[1].indexOf(StrUtil.SLASH) == -1){
                    return true;
                }
            }
            return false;
        }).collect(Collectors.toList());

        List<TreeVo<ResourceVo>> folderChildResources = folderFilePaths.stream()
                .filter(s -> SchemaFileUtil.filterFile(s))
                .map(s -> {
                    TreeVo<ResourceVo> resourceVoTreeDto = createTreeDto(s, false, ResourceType.domain_model);
                    return resourceVoTreeDto;
                })
                .collect(Collectors.toList());

        if(folderResource.getChildren() == null){
            folderResource.setChildren(new ArrayList<>());
        }
        folderResource.getChildren().addAll(folderChildResources);
        return folderResource;
    }

    private TreeVo<ResourceVo> createTreeDto(String fullPath, boolean isfolder, ResourceType resourceType){
        ResourceVo resourceVo = createResource(fullPath, isfolder, resourceType);
        TreeVo treeDto = new TreeVo();
        treeDto.setId(fullPath);
        treeDto.setTitle(resourceVo.getName());

        if(resourceVo.isEnabled()){
            treeDto.setTitle(resourceVo.getName());
        }else{
            if(!isfolder){
                treeDto.setTitle(resourceVo.getName() + "    【未启动】");
            }

        }

        treeDto.setData(resourceVo);
        treeDto.setIconSkin(resourceType.getIcon());
        if(isfolder){
            treeDto.setSpread(true);
        }

        //当不是元数据节点则增加元数据节点树
        if(SchemaFileUtil.isFile(fullPath)){
            List<TreeVo<ResourceVo>> metaNodes = getMetaNodes(fullPath);
            if(metaNodes != null){
                if(treeDto.getChildren() == null){
                    treeDto.setChildren(new ArrayList<>());
                }
                treeDto.getChildren().addAll(metaNodes);
            }
        }

        treeDto.setHref("http://localhost:8080/domain-resource.html");

        return treeDto;
    }


    private ResourceVo createResource(String fullPath, boolean isfolder, ResourceType resourceType){
        String name = SchemaFileUtil.getPathName(fullPath);
        ResourceVo resource = new ResourceVo();
        resource.setName(name);
        resource.setPath(fullPath);
        resource.setType(resourceType);
        resource.setFolder(isfolder);
        if(!isfolder){
            setFileResourceVo(resource, fullPath);
        }

        return resource;
    }

    private void setFileResourceVo(ResourceVo resourceVo, String fullPath){
        String schemaStr = StrUtil.utf8Str(resourceManager.read(fullPath));
        JSONObject jsonObject = JSONUtil.parseObj(schemaStr);
        Boolean enabled = jsonObject.getBool("enabled");
        resourceVo.setEnabled(enabled);
        resourceVo.setSchema(schemaStr);
    }

    // /**
    //  * 获取文件的启用属性
    //  * @param fullPath
    //  * @return
    //  */
    // private boolean getEnabledProp(String fullPath){
    //     String schemaStr = StrUtil.utf8Str(resourceManager.read(fullPath));
    //     JSONObject jsonObject = JSONUtil.parseObj(schemaStr);
    //     Boolean enabled = jsonObject.getBool("enabled");
    //     return enabled;
    // }

    private List<TreeVo<ResourceVo>> getMetaNodes(String fullPath){
        String value = StrUtil.utf8Str(resourceManager.read(fullPath));
        JSONObject jsonObject = JSONUtil.parseObj(value);
        JSONArray jsonArray = jsonObject.getJSONArray("fields");

        if(jsonArray != null){
            return jsonArray.stream().map(o -> {
                JSONObject field = (JSONObject)o;
                String name = field.getStr("name");

                return createMetaTreeDto(name, fullPath + "#/fields/" + name, false, ResourceType.domain_model_field);
            }).collect(Collectors.toList());

        }
        return null;
    }



    private TreeVo<ResourceVo> createMetaTreeDto(String nodeName, String fullPath, boolean isfolder, ResourceType resourceType){
        ResourceVo resourceVo = createMetaNodeResource(nodeName, fullPath, isfolder, resourceType);
        TreeVo treeDto = new TreeVo();
        treeDto.setId(fullPath);
        treeDto.setTitle(resourceVo.getName());
        treeDto.setData(resourceVo);
        treeDto.setIconSkin(resourceVo.getType().getIcon());
        if(isfolder){
            treeDto.setSpread(true);
        }

        return treeDto;
    }


    private ResourceVo createMetaNodeResource(String nodeName, String fullPath, boolean isfolder, ResourceType resourceType){
        ResourceType metaNodeResourceType = getPrimaryKeyResourceType(fullPath);
        if(metaNodeResourceType == null){
            metaNodeResourceType = resourceType;
        }

        ResourceVo resource = new ResourceVo();
        resource.setName(nodeName);
        resource.setPath(fullPath);
        resource.setType(metaNodeResourceType);
        resource.setFolder(isfolder);
        return resource;
    }

    private ResourceType getPrimaryKeyResourceType(String fullPath){
        String schemaStr = schemaReader.read(fullPath);
        JSONObject jsonObject = JSONUtil.parseObj(schemaStr);
        Boolean primaryKey = jsonObject.getBool("primaryKey", false);
        if(primaryKey){
            return ResourceType.domain_model_field_primary_key;
        }else{
            return null;
        }
    }
}
